import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.util.Random;

public class Game2048 extends JFrame {
    private static final int SIZE = 4;
    private static final int TILE_SIZE = 100;
    private static final int GRID_PADDING = 15;
    private static final int WINDOW_WIDTH = TILE_SIZE * SIZE + GRID_PADDING * (SIZE + 1);
    private static final int WINDOW_HEIGHT = TILE_SIZE * SIZE + GRID_PADDING * (SIZE + 1) + 100;

    private int[][] board;
    private Random random;
    private boolean gameOver;
    private boolean win;
    private int score;
    private JLabel scoreLabel;
    private TilePanel tilePanel;

    public Game2048() {
        board = new int[SIZE][SIZE];
        random = new Random();
        gameOver = false;
        win = false;
        score = 0;

        initUI();
        addRandomTile();
        addRandomTile();
        tilePanel.repaint();
    }

    private void initUI() {
        setTitle("2048游戏");
        setSize(WINDOW_WIDTH, WINDOW_HEIGHT);
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setLocationRelativeTo(null);
        setResizable(false);

        setLayout(new BorderLayout());

        // 创建顶部面板，显示分数
        JPanel topPanel = new JPanel();
        topPanel.setLayout(new FlowLayout(FlowLayout.CENTER, 20, 10));
        topPanel.setBackground(new Color(0xbbada0));

        JLabel titleLabel = new JLabel("2048");
        titleLabel.setFont(new Font("Arial", Font.BOLD, 36));
        titleLabel.setForeground(new Color(0x776e65));
        topPanel.add(titleLabel);

        JPanel scorePanel = new JPanel();
        scorePanel.setLayout(new BoxLayout(scorePanel, BoxLayout.Y_AXIS));
        scorePanel.setBackground(new Color(0xbbada0));
        JLabel scoreTitle = new JLabel("分数");
        scoreTitle.setFont(new Font("Arial", Font.BOLD, 14));
        scoreTitle.setForeground(new Color(0xeee4da));
        scorePanel.add(scoreTitle);
        scoreLabel = new JLabel("0");
        scoreLabel.setFont(new Font("Arial", Font.BOLD, 20));
        scoreLabel.setForeground(Color.WHITE);
        scorePanel.add(scoreLabel);
        topPanel.add(scorePanel);

        JButton newGameButton = new JButton("新游戏");
        newGameButton.setFont(new Font("Arial", Font.BOLD, 14));
        newGameButton.setBackground(new Color(0xf1b078));
        newGameButton.setForeground(Color.WHITE);
        newGameButton.setFocusPainted(false);
        newGameButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                resetGame();
            }
        });
        topPanel.add(newGameButton);

        add(topPanel, BorderLayout.NORTH);

        // 创建游戏面板
        tilePanel = new TilePanel();
        tilePanel.setBackground(new Color(0xbbada0));
        add(tilePanel, BorderLayout.CENTER);

        // 添加键盘监听器
        addKeyListener(new KeyAdapter() {
            @Override
            public void keyPressed(KeyEvent e) {
                if (gameOver || win) {
                    return;
                }

                boolean moved = false;
                switch (e.getKeyCode()) {
                    case KeyEvent.VK_UP:
                        moved = moveUp();
                        break;
                    case KeyEvent.VK_DOWN:
                        moved = moveDown();
                        break;
                    case KeyEvent.VK_LEFT:
                        moved = moveLeft();
                        break;
                    case KeyEvent.VK_RIGHT:
                        moved = moveRight();
                        break;
                    default:
                        break;
                }

                if (moved) {
                    addRandomTile();
                    checkGameState();
                    tilePanel.repaint();
                    scoreLabel.setText(String.valueOf(score));
                }
            }
        });

        setFocusable(true);
    }

    private void addRandomTile() {
        int emptyCells = 0;
        for (int i = 0; i < SIZE; i++) {
            for (int j = 0; j < SIZE; j++) {
                if (board[i][j] == 0) {
                    emptyCells++;
                }
            }
        }

        if (emptyCells == 0) {
            return;
        }

        int position = random.nextInt(emptyCells) + 1;
        int count = 0;
        int value = random.nextDouble() < 0.9 ? 2 : 4;

        for (int i = 0; i < SIZE; i++) {
            for (int j = 0; j < SIZE; j++) {
                if (board[i][j] == 0) {
                    count++;
                    if (count == position) {
                        board[i][j] = value;
                        return;
                    }
                }
            }
        }
    }

    private boolean moveUp() {
        boolean moved = false;
        for (int j = 0; j < SIZE; j++) {
            int[] merged = new int[SIZE];
            for (int i = 1; i < SIZE; i++) {
                if (board[i][j] != 0) {
                    int prev = i - 1;
                    while (prev >= 0 && board[prev][j] == 0) {
                        prev--;
                    }

                    if (prev == -1) {
                        board[0][j] = board[i][j];
                        if (i != 0) {
                            board[i][j] = 0;
                            moved = true;
                        }
                    } else if (board[prev][j] == board[i][j] && merged[prev] == 0) {
                        board[prev][j] *= 2;
                        score += board[prev][j];
                        board[i][j] = 0;
                        merged[prev] = 1;
                        moved = true;
                    } else if (prev + 1 != i) {
                        board[prev + 1][j] = board[i][j];
                        board[i][j] = 0;
                        moved = true;
                    }
                }
            }
        }
        return moved;
    }

    private boolean moveDown() {
        boolean moved = false;
        for (int j = 0; j < SIZE; j++) {
            int[] merged = new int[SIZE];
            for (int i = SIZE - 2; i >= 0; i--) {
                if (board[i][j] != 0) {
                    int next = i + 1;
                    while (next < SIZE && board[next][j] == 0) {
                        next++;
                    }

                    if (next == SIZE) {
                        board[SIZE - 1][j] = board[i][j];
                        if (i != SIZE - 1) {
                            board[i][j] = 0;
                            moved = true;
                        }
                    } else if (board[next][j] == board[i][j] && merged[next] == 0) {
                        board[next][j] *= 2;
                        score += board[next][j];
                        board[i][j] = 0;
                        merged[next] = 1;
                        moved = true;
                    } else if (next - 1 != i) {
                        board[next - 1][j] = board[i][j];
                        board[i][j] = 0;
                        moved = true;
                    }
                }
            }
        }
        return moved;
    }

    private boolean moveLeft() {
        boolean moved = false;
        for (int i = 0; i < SIZE; i++) {
            int[] merged = new int[SIZE];
            for (int j = 1; j < SIZE; j++) {
                if (board[i][j] != 0) {
                    int prev = j - 1;
                    while (prev >= 0 && board[i][prev] == 0) {
                        prev--;
                    }

                    if (prev == -1) {
                        board[i][0] = board[i][j];
                        if (j != 0) {
                            board[i][j] = 0;
                            moved = true;
                        }
                    } else if (board[i][prev] == board[i][j] && merged[prev] == 0) {
                        board[i][prev] *= 2;
                        score += board[i][prev];
                        board[i][j] = 0;
                        merged[prev] = 1;
                        moved = true;
                    } else if (prev + 1 != j) {
                        board[i][prev + 1] = board[i][j];
                        board[i][j] = 0;
                        moved = true;
                    }
                }
            }
        }
        return moved;
    }

    private boolean moveRight() {
        boolean moved = false;
        for (int i = 0; i < SIZE; i++) {
            int[] merged = new int[SIZE];
            for (int j = SIZE - 2; j >= 0; j--) {
                if (board[i][j] != 0) {
                    int next = j + 1;
                    while (next < SIZE && board[i][next] == 0) {
                        next++;
                    }

                    if (next == SIZE) {
                        board[i][SIZE - 1] = board[i][j];
                        if (j != SIZE - 1) {
                            board[i][j] = 0;
                            moved = true;
                        }
                    } else if (board[i][next] == board[i][j] && merged[next] == 0) {
                        board[i][next] *= 2;
                        score += board[i][next];
                        board[i][j] = 0;
                        merged[next] = 1;
                        moved = true;
                    } else if (next - 1 != j) {
                        board[i][next - 1] = board[i][j];
                        board[i][j] = 0;
                        moved = true;
                    }
                }
            }
        }
        return moved;
    }

    private void checkGameState() {
        // 检查是否获胜
        for (int i = 0; i < SIZE; i++) {
            for (int j = 0; j < SIZE; j++) {
                if (board[i][j] >= 2048) {
                    win = true;
                    JOptionPane.showMessageDialog(this, "恭喜你，赢得了游戏！", "游戏胜利", JOptionPane.INFORMATION_MESSAGE);
                    return;
                }
            }
        }

        // 检查是否还有空格子
        for (int i = 0; i < SIZE; i++) {
            for (int j = 0; j < SIZE; j++) {
                if (board[i][j] == 0) {
                    return;
                }
            }
        }

        // 检查是否还能移动
        for (int i = 0; i < SIZE; i++) {
            for (int j = 0; j < SIZE - 1; j++) {
                if (board[i][j] == board[i][j + 1]) {
                    return;
                }
            }
        }

        for (int j = 0; j < SIZE; j++) {
            for (int i = 0; i < SIZE - 1; i++) {
                if (board[i][j] == board[i + 1][j]) {
                    return;
                }
            }
        }

        // 如果以上条件都不满足，游戏结束
        gameOver = true;
        JOptionPane.showMessageDialog(this, "游戏结束！", "游戏结束", JOptionPane.INFORMATION_MESSAGE);
    }

    private void resetGame() {
        for (int i = 0; i < SIZE; i++) {
            for (int j = 0; j < SIZE; j++) {
                board[i][j] = 0;
            }
        }
        gameOver = false;
        win = false;
        score = 0;
        scoreLabel.setText("0");
        addRandomTile();
        addRandomTile();
        tilePanel.repaint();
    }

    private class TilePanel extends JPanel {
        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2d = (Graphics2D) g;
            g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

            // 绘制网格背景
            g2d.setColor(new Color(0xc9b9a9));
            for (int i = 0; i < SIZE; i++) {
                for (int j = 0; j < SIZE; j++) {
                    int x = GRID_PADDING + j * (TILE_SIZE + GRID_PADDING);
                    int y = GRID_PADDING + i * (TILE_SIZE + GRID_PADDING);
                    g2d.fillRoundRect(x, y, TILE_SIZE, TILE_SIZE, 14, 14);
                }
            }

            // 绘制方块
            for (int i = 0; i < SIZE; i++) {
                for (int j = 0; j < SIZE; j++) {
                    int value = board[i][j];
                    if (value != 0) {
                        int x = GRID_PADDING + j * (TILE_SIZE + GRID_PADDING);
                        int y = GRID_PADDING + i * (TILE_SIZE + GRID_PADDING);

                        // 设置方块颜色
                        Color bgColor = getTileColor(value);
                        g2d.setColor(bgColor);
                        g2d.fillRoundRect(x, y, TILE_SIZE, TILE_SIZE, 14, 14);

                        // 设置文字颜色和大小
                        Color textColor = value <= 4 ? new Color(0x776e65) : Color.WHITE;
                        Font font = new Font("Arial", Font.BOLD, getFontSize(value));

                        // 绘制数字
                        g2d.setColor(textColor);
                        g2d.setFont(font);
                        String text = String.valueOf(value);
                        FontMetrics fm = g2d.getFontMetrics();
                        int textWidth = fm.stringWidth(text);
                        int textHeight = fm.getHeight();
                        g2d.drawString(text, x + (TILE_SIZE - textWidth) / 2, y + TILE_SIZE / 2 + textHeight / 4);
                    }
                }
            }
        }

        private Color getTileColor(int value) {
            switch (value) {
                case 2: return new Color(0xeee4da);
                case 4: return new Color(0xede0c8);
                case 8: return new Color(0xf2b179);
                case 16: return new Color(0xf59563);
                case 32: return new Color(0xf67c5f);
                case 64: return new Color(0xf65e3b);
                case 128: return new Color(0xedcf72);
                case 256: return new Color(0xedcc61);
                case 512: return new Color(0xedc850);
                case 1024: return new Color(0xedc53f);
                case 2048: return new Color(0xedc22e);
                default: return new Color(0x3c3a32);
            }
        }

        private int getFontSize(int value) {
            if (value < 100) return 36;
            if (value < 1000) return 32;
            return 28;
        }
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(() -> {
            Game2048 game = new Game2048();
            game.setVisible(true);
        });
    }
}    
